package edu.nus.mtech.sem1.ca.data;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.nus.mtech.sem1.ca.Payment;
import edu.nus.mtech.sem1.ca.auth.User;
import edu.nus.mtech.sem1.ca.auth.UserRole;
import edu.nus.mtech.sem1.ca.cust.Customer;
import edu.nus.mtech.sem1.ca.cust.complaint.Complaint;
import edu.nus.mtech.sem1.ca.plan.Account;
import edu.nus.mtech.sem1.ca.txn.Transaction;
import edu.nus.mtech.sem1.ca.utils.Logger;


/**
 *  Acts as a database. Each Collection encapsulated inside the class will be transformed 
 * 
 * 	1)	Either into a table when the app is ported on to a DBMS or
 *  2)	Retained as a project configuration file in XML or .properties
 *
 */
public class Database {
	
	private static Database singletonInstance;
	
	//The only reason for using Maps for most of the collection is for easy lookup through the key. Though list and 
	//set could be more appropriate, the lookup time in a time is way way faster in a hash-based map.

	
	private Map<String, User> userMap=null;
	private Map<String, Customer> customerMap=null;
	private Map<String, Set<Complaint>> complaintMap=null;
	private Map<String, List<String>> userRoleAccessControlMapping=null;
	private Map<String, Float> rateMap=null; 
	private Map<String, Set<Transaction>> transactionMap=null;
	private Map<String, Account> accountMap=null;
	private Map<String, Payment> paymentHistoryMap=null;
	
	private Database(){};
	
	
	protected static Database getInstance(){
		if (singletonInstance==null){
			singletonInstance=new Database();
		}
		return singletonInstance;
	}
	
	public List<String> getAccessesForUserRole(UserRole userRole){
		if (userRoleAccessControlMapping!=null){
			return (userRoleAccessControlMapping.get(userRole.toString()));	
		}
		return new ArrayList<String>();
	}


	protected void setUserRoleAccessControlMapping(Map<String, List<String>> userRoleAccessControlMapping) {
		this.userRoleAccessControlMapping = userRoleAccessControlMapping;
	}


	public Map<String, User> getUserMap() {
		return userMap;
	}

	public void setUserMap(Map<String, User> userMap) {
		this.userMap = userMap;
	}

	public Map<String, Customer> getCustomerMap() {
		return customerMap;
	}


	public void setCustomerMap(Map<String, Customer> customerMap) {
		this.customerMap = customerMap;
	}

	public Map<String, Set<Complaint>> getComplaintMap() {
		return complaintMap;
	}


	public void setComplaintMap(Map<String, Set<Complaint>> complaintMap) {
		this.complaintMap = complaintMap;
	}


	/**
	 * Creates a new Complaint Set for a customer if no complaints has been lodged previously.
	 * Else, adds to the existing set. Remember, the Set always calls the equals method for checking duplicates. 
	 * So, no duplicate complaints are allowed naturally.
	 * 
	 * @param nric
	 * @param complaint
	 */
	public void addToComplaintMap(String nric, Complaint complaint) {
		if (complaintMap.get(nric)!=null){
			Set<Complaint> tmpComplaintSet = complaintMap.get(nric);
			tmpComplaintSet=cleanupEarlierComplaint(tmpComplaintSet, complaint);
			tmpComplaintSet.add(complaint);
			complaintMap.put(nric, tmpComplaintSet);
		}
		else{
			Set<Complaint> newComplaintSet=new HashSet<Complaint>();
			newComplaintSet.add(complaint);
			complaintMap.put(nric, newComplaintSet);
		}
	}


	/**
	 * Cleans up previously existing complaint object for clean addition
	 * @param tmpComplaintSet
	 * @param incomingComplaint
	 * @return
	 */
	private Set<Complaint> cleanupEarlierComplaint(Set<Complaint> tmpComplaintSet, Complaint incomingComplaint) {
		if (tmpComplaintSet==null){
			return new HashSet<Complaint>();
		}
		
		Set<Complaint> returnComplaint=new HashSet<Complaint>(tmpComplaintSet); //make a copy
		
		for (Complaint complaint : returnComplaint) {
			if (complaint.getComplaintNo()!=null && complaint.getComplaintNo().equalsIgnoreCase(incomingComplaint.getComplaintNo())){
				returnComplaint.remove(incomingComplaint);
				break;
			}
		}
		
		return returnComplaint;
	}


	public Map<String, Float> getRateMap() {
		return rateMap;
	}


	public void setRateMap(Map<String, Float> rateMap) {
		this.rateMap = rateMap;
	}


	public Map<String, Set<Transaction>> getTransactionMap() {
		return transactionMap;
	}


	public void setTransactionMap(Map<String, Set<Transaction>> transactionMap) {
		this.transactionMap = transactionMap;
	}


	public Map<String, Account> getAccountMap() {
		return accountMap;
	}


	public void setAccountMap(Map<String, Account> accountMap) {
		this.accountMap = accountMap;
	}

	public void setPaymentHistoryMap(Map<String, Payment> paymentHistoryMap) {
		this.paymentHistoryMap = paymentHistoryMap;
	}


	public Map<String, Payment> getPaymentHistoryMap() {
		return paymentHistoryMap;
	}

	public void addToCustomerMap(String nric, Customer customer){
		this.customerMap.put(nric, customer);
	}
	
	public void removeFromCustomerMap(String nric){
		this.customerMap.remove(nric);
	}

	/*public Map<String,Double> ratesDb;
	public Map<mobileNo:String, transactions:ArrayList<Transaction>> mobileCallTransaction;
	public Map<landlineNo:String, transactions:ArrayList<Transaction>> landlineCallTransaction;
	public Map<mobileNo:String, transactions:ArrayList<Transaction>> excessDataTransaction;
	public Map<accountNos:String,previousBill:double,paidAmt:double> paymentdetails;*/
	
	
}
